package com.wstuo.common.scheduledTask.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.apache.struts2.json.JSONException;
import org.apache.struts2.json.JSONUtil;
import org.quartz.Job;
import org.quartz.SchedulerException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.expression.ParseException;
import org.springframework.transaction.annotation.Transactional;

import com.wstuo.common.config.category.dao.IEventCategoryDAO;
import com.wstuo.common.config.category.entity.EventCategory;
import com.wstuo.common.scheduledTask.dao.IScheduledTaskDAO;
import com.wstuo.common.scheduledTask.dto.ScheduledTaskDTO;
import com.wstuo.common.scheduledTask.dto.ScheduledTaskGridDTO;
import com.wstuo.common.scheduledTask.dto.ScheduledTaskQueryDTO;
import com.wstuo.common.scheduledTask.dto.ScheduledTaskRequestDTO;
import com.wstuo.common.scheduledTask.entity.ScheduledTask;
import com.wstuo.common.scheduledTask.utils.CronExpConversion;
import com.wstuo.common.scheduledTask.utils.QuartzManager;
import com.wstuo.common.dto.PageDTO;
import com.wstuo.common.exception.ApplicationException;
import com.wstuo.common.file.csv.CSVReader;
import com.wstuo.common.security.utils.FileEncodeUtils;
import com.wstuo.common.util.AppliactionBaseListener;
import com.wstuo.common.util.StringUtils;
import com.wstuo.common.util.TimeUtils;


/**
 * 定期任务Service 类
 * @author WSTUO
 *
 */
public class ScheduledTaskService implements IScheduledTaskService {
	private final static Logger LOGGER = Logger.getLogger(ScheduledTaskService.class);
	@Autowired
	private IScheduledTaskDAO scheduledTaskDAO;
	@Autowired
	private IEventCategoryDAO eventCategoryDAO;
	private CronExpConversion cornExp=new CronExpConversion();
	private QuartzManager quartzManager=new QuartzManager(); 
	/**
	 * 分页查询
	 * @param queryDTO
	 * @return PageDTO
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public PageDTO findPageScheduledTask(final ScheduledTaskQueryDTO queryDTO){
		PageDTO p = scheduledTaskDAO.findPageScheduledTask(queryDTO);
		List<ScheduledTask> entityList=(List<ScheduledTask>)p.getData();
		List<ScheduledTaskGridDTO> dtoList=new ArrayList<ScheduledTaskGridDTO>(entityList.size());
		for(ScheduledTask entity:entityList){
			ScheduledTaskGridDTO dto=new ScheduledTaskGridDTO();
			this.entity2dto(entity,dto);
			dtoList.add(dto);
		}
		p.setData(dtoList);
		p.setRows(queryDTO.getLimit());
		return p;
	}
	/**
	 * String转换为Long[]
	 * @param str
	 * @return Long[]
	 */
	private Long[] stringConvertLongs(String str){
		String[] strs=str.split(",");
		Long[] ids=new Long[strs.length];
		for (int i = 0; i < strs.length; i++) {
			ids[i]=Long.parseLong(strs[i]);
		}
		return ids;
	}
	/**
	 * jason转换为DTO
	 * @param entity
	 * @param requestDTO
	 */
	private ScheduledTaskRequestDTO jasonToDto(ScheduledTask entity){
		ScheduledTaskRequestDTO requestDTO = null;
		//json to dto
		try {
			if(entity!=null&&entity.getRequestDtoJson()!=null){
				Object object = JSONUtil.deserialize(entity.getRequestDtoJson());
				requestDTO=(ScheduledTaskRequestDTO)JSONObject.toBean(JSONObject.fromObject(object),Class.forName("com.wstuo.common.scheduledTask.dto.ScheduledTaskRequestDTO"));
			}
		}catch (ClassNotFoundException e) {
			throw new ApplicationException("ERROR_CONVERT_JSON_TO_BEAN/n"+e.getMessage(),e);
		}catch (JSONException e) {
			throw new ApplicationException("ERROR_CONVERT_JSON_TO_BEAN/n"+e.getMessage(),e);
		}
		return requestDTO;
	}
	/**
	 * 转换ScheduledTaskRequestDTO的值
	 */
	private void convertScheduledTaskRequestDTO(ScheduledTaskRequestDTO requestDTO){
		if(requestDTO!=null&&requestDTO.getCiids()!=null){
			String ciIds=requestDTO.getCiids();
			if(StringUtils.hasText(ciIds)){
				Long[] ids=stringConvertLongs(ciIds);
				requestDTO.setRelatedConfigureItemNos(ids);
			}
		}
		if(requestDTO!=null&&requestDTO.getRequestServiceDirNos()!=null){
			String serviceDirNos=requestDTO.getRequestServiceDirNos();
			if(StringUtils.hasText(serviceDirNos)){
				Long[] ids=stringConvertLongs(serviceDirNos);
				requestDTO.setRequestServiceDirNo(ids);
				requestDTO.setServiceDirNames(setServiceDirNames(serviceDirNos));
			}
		}
	}
	/**
	 * set ServiceDirNames 
	 * @param serviceDirNos
	 * @return String
	 */
	public String setServiceDirNames(String serviceDirNos){
		StringBuffer serviceDirNames = new StringBuffer("");
		String[] strs=serviceDirNos.split(",");
		Long[] ids=new Long[strs.length];
		for (int i = 0; i < strs.length; i++) {
			ids[i]=Long.parseLong(strs[i]);
			EventCategory eventCategory = eventCategoryDAO.findById(ids[i]);
			if(eventCategory!=null){
				serviceDirNames.append(eventCategory.getEventName() + ",");
			}
		}
		if(serviceDirNames!=null && StringUtils.hasText(serviceDirNames.toString())){
			String dirNames = serviceDirNames.toString();
			return dirNames.substring(0, dirNames.length() - 1);
		}
		return "";
	}
	/**
	 * entity2dto
	 * @param entity
	 * @param dto
	 */
	private void entity2dto(ScheduledTask entity,ScheduledTaskGridDTO dto){
		ScheduledTaskRequestDTO requestDTO=new ScheduledTaskRequestDTO();
		//json to dto
		requestDTO = jasonToDto(entity);
		convertScheduledTaskRequestDTO(requestDTO);
		
		dto.setScheduledTaskId(entity.getScheduledTaskId());
		if(requestDTO!=null){
			dto.setTitle(requestDTO.getEtitle());
			dto.setDescription(requestDTO.getCreatedByName());
			dto.setCompanyName(requestDTO.getCompanyName());
		}
		BeanUtils.copyProperties(entity, dto);
	}
	/**
	 * 根据ID获取定期任务详细
	 * @param id
	 * @return ScheduledTaskDTO
	 */
	@Transactional
	public ScheduledTaskDTO findScheduledTaskById(final Long id){
		ScheduledTaskDTO scheduledTaskDTO=new ScheduledTaskDTO();
		ScheduledTask entity=scheduledTaskDAO.findById(id);
		ScheduledTaskDTO.entity2dto(entity, scheduledTaskDTO);
		ScheduledTaskRequestDTO requestDTO=new ScheduledTaskRequestDTO();
		//json to dto
		requestDTO = jasonToDto(entity);
		convertScheduledTaskRequestDTO(requestDTO);
		scheduledTaskDTO.setRequestDTO(requestDTO);	
		
		return scheduledTaskDTO;
	}
	
	/**
	 * 定期任务时间转换
	 * @param date
	 * @return Date
	 */
	private Date scheduledTaskDateFormat(Date date,String fixedTime){
		String date_str =TimeUtils.format(date, TimeUtils.DATE_PATTERN)+fixedTime;
		Date newDate = TimeUtils.parse(date_str,TimeUtils.DATETIME_PATTERN);
		return newDate;
	}
	/**
	 * 添加一个定期任务
	 * @param dto
	 * @param entity
	 */
	private void addQuartzManagerJob(ScheduledTaskRequestDTO dto,ScheduledTask entity){
		ApplicationContext ctx =AppliactionBaseListener.ctx;
		if(ctx!=null){
			Job job=(Job)ctx.getBean(entity.getBeanId());
			//如果是一次性计划，则不需要结束时间
			Date taskEndDate=null;
			if(!entity.getTimeType().equals(ONOFF)){
				taskEndDate=entity.getTaskEndDate();
			}
			Long scheduledTaskId=entity.getScheduledTaskId();
			try {
				quartzManager.addJob(
						JOB_NAME+scheduledTaskId, 
						JOB_GROUP_NAME+scheduledTaskId,
						TRIGGER_NAME+scheduledTaskId, 
						TRIGGER_GROUP_NAME+scheduledTaskId, 
						job,
						entity.getCronExpression(),
						entity.getTaskDate(),
						taskEndDate,
						dto,
						entity.getReportId()
				
				);
			} catch (ParseException e) {
				throw new ApplicationException("ERROR_CRONEXPRESSION_FAILURE",e);
			} catch (SchedulerException e) {
				throw new ApplicationException("ERROR_CRONEXPRESSION_FAILURE",e);
			}
		}
	}
	/**
	 * 修改一个定期任务
	 * @param dto
	 * @param entity
	 */
	private void modifyQuartzManagerJobTime(ScheduledTaskRequestDTO dto,ScheduledTask entity){
		//如果是一次性计划，则不需要结束时间
		Date taskEndDate=null;
		if(!entity.getTimeType().equals(ONOFF)){
			taskEndDate=entity.getTaskEndDate();
		}
		Long scheduledTaskId=entity.getScheduledTaskId();
		try {
			quartzManager.modifyJobTime(
					JOB_NAME+scheduledTaskId,
					JOB_GROUP_NAME+scheduledTaskId,
					TRIGGER_NAME+scheduledTaskId, 
					TRIGGER_GROUP_NAME+scheduledTaskId, 
					entity.getCronExpression(),
					entity.getTaskDate(),//开始时间
					taskEndDate,
					dto,
					entity.getReportId());
		} catch (ParseException e) {
			throw new ApplicationException("ERROR_CRONEXPRESSION_FAILURE",e);
		} catch (SchedulerException e) {
			throw new ApplicationException("ERROR_CRONEXPRESSION_FAILURE",e);
		}
	}
	/**
	 * dto 转 entity 
	 * @param dto
	 * @param entity
	 */
	private void dto2entity(ScheduledTaskDTO dto,ScheduledTask entity){
		if(entity.getTaskEndDate()!=null){
			entity.setTaskDate(scheduledTaskDateFormat(entity.getTaskDate(),INITTIME));//开始时间
			entity.setTaskEndDate(scheduledTaskDateFormat(entity.getTaskEndDate(),LASTTIME));//结束时间
		}
		entity.setCompanyNo(dto.getRequestDTO().getCompanyNo());
		entity.setFormId(dto.getRequestDTO().getFormId());
		//时间转成triggerTime
		entity.setCronExpression(cornExp.convertDateToCronExp(dto));
		//dto to json
		try {
			entity.setRequestDtoJson(JSONUtil.serialize(dto.getRequestDTO()));
		} catch (JSONException e) {
			throw new ApplicationException("ERROR_CONVERT_DTO_TO_JSON/n",e);
		}
	}
	
	/**
	 * 添加定期任务
	 * @param dto ScheduledTaskDTO
	 */
	@Transactional
	public void saveScheduledTask(final ScheduledTaskDTO dto){
		ScheduledTask entity=new ScheduledTask();
		ScheduledTaskDTO.dto2entity(dto, entity);
		dto2entity(dto, entity);
		scheduledTaskDAO.save(entity);
		dto.setScheduledTaskId(entity.getScheduledTaskId());
		//添加一个定期任务
		addQuartzManagerJob(dto.getRequestDTO(), entity);
	}
	/**
	 * 编辑定期任务
	 * @param dto ScheduledTaskDTO
	 */
	@Transactional
	public void editScheduledTask(final ScheduledTaskDTO dto){
		ScheduledTask entity=null;
		String flag=EDIT_SCHEDULEDTASK;
		if(dto.getScheduledTaskId()!=null){
			entity=scheduledTaskDAO.findById(dto.getScheduledTaskId());
			if(entity==null){
				entity=new ScheduledTask();
				flag=NEW_SCHEDULEDTASK;
	        	throw new ApplicationException("ERROR_DATA_NO_LONGER_EXISTS\n");
			}else{
	        	dto.setBeanId(entity.getBeanId());
	        }
			ScheduledTaskDTO.dto2entity(dto, entity);
			dto2entity(dto, entity);
			entity.setLastUpdateTime(new Date());
			entity=scheduledTaskDAO.merge(entity);
			//修改任务时间
			if(EDIT_SCHEDULEDTASK.equals(flag)){
				modifyQuartzManagerJobTime(dto.getRequestDTO(), entity);
			}else{
				addQuartzManagerJob(dto.getRequestDTO(), entity);
			}
		}
	}
	/**
	 * 删除定期任务
	 * @param ids
	 */
	@Transactional
	public void deleteScheduledTask(final Long[] ids){
		scheduledTaskDAO.deleteByIds(ids);
	}
	
	@Transactional
	public void removeJob(final Long[] ids){
		//移除任务
		for(Long id:ids){
			try {
				quartzManager.removeJob(JOB_NAME+id,JOB_GROUP_NAME+id,TRIGGER_NAME+id,TRIGGER_GROUP_NAME+id);
			} catch (SchedulerException e) {
				throw new ApplicationException("ERROR_REMOVEJOB_FAILURE",e);
			}
		}
	}
	
	/**
	 * 对所有任务生成定期
	 */
	public void generateScheduledTask(){
		List<ScheduledTask> allScheduled=scheduledTaskDAO.findAll();
		ScheduledTaskRequestDTO strDTO=new ScheduledTaskRequestDTO();
		if(allScheduled!=null && allScheduled.size()>0){
			for(ScheduledTask entity:allScheduled){
				//json to dto
				strDTO = jasonToDto(entity);
				if(!TimeUtils.beForNowSystemDate(entity.getTaskEndDate())){
					//如果结束时间不等于空，并且小于当前时间，则是过期的任务
					try {
						addQuartzManagerJob(strDTO, entity);
					} catch (Exception e) {
						// TODO: handle exception
					    LOGGER.error(entity.getCronExpression()+":任务调度出现异常");
					}
					
				}
			}
		}
		System.out.println("--------------------------------");
	}
	
	/**
	 * 定期任务导入
	 * @param importFile
	 * @return String
	 */
	@Transactional
	public String importScheduledTask(File importFile) {
    	String parameter="";
    	Reader rd =null;
    	CSVReader reader = null;
    	try {
			String fileEncode = FileEncodeUtils.getFileEncode(importFile);
			rd = new InputStreamReader(new FileInputStream(importFile), fileEncode);// 以字节流方式读取数据
			reader=new CSVReader(rd);
			String [] line=null;
			while((line=reader.readNext())!=null){
				ScheduledTaskDTO sc=new ScheduledTaskDTO();
				arrayToDTO(line, sc);
			}
			parameter=SUCCESS;
    	}catch (Exception ex) {
    		LOGGER.error(ex);
    		parameter=FALL;
		}finally {
			try {
				if(rd!=null){
					rd.close();
				}
				if(reader!=null){
					reader.close();
				}
			} catch (IOException e) {
				LOGGER.error(e);
			}
		}
    	return parameter;
	}
	/**
	 * 字符串数组转换成ScheduledTaskDTO
	 * @param line
	 * @param sc
	 */
	private void arrayToDTO(String[] line, ScheduledTaskDTO sc) {
		sc.setBeanId(line[0]);
		sc.setCyclicalDay(Long.parseLong(line[1]));
		sc.setCyclicalMinute(Long.parseLong(line[2]));
		sc.setReportId(Long.parseLong(line[3]));
		sc.getRequestDTO().setCompanyNo(Long.parseLong(line[4]));
		sc.getRequestDTO().setEtitle(line[5]);
		sc.setScheduledTaskType(line[6]);
		sc.setTaskDate(TimeUtils.parse(line[7],TimeUtils.DATETIME_PATTERN));
		sc.setTaskEndDate(TimeUtils.parse(line[8],TimeUtils.DATETIME_PATTERN));
		sc.setTaskHour(Long.parseLong(line[9]));
		sc.setTaskMinute(Long.parseLong(line[10]));
		sc.setTimeType(line[11]);
		saveScheduledTask(sc);
	}
	/**
	 * Long[] 转换为 String
	 * @param ids
	 * @return String
	 */
	private String longsConvertString(Long[] ids){
		String str="";
		for (Long l : ids) {
			str+=","+l;
		}
		str = str.substring(1);
		return str;
	}
	/**
	 * 转换ScheduledTaskDTO的值
	 * @param scheduledTaskDTO
	 * @param scheduledTaskRequestDTO
	 * @param cinos
	 * @param serviceDirNos
	 * @return ScheduledTaskDTO
	 */
	public ScheduledTaskDTO convertScheduledTaskDTOValue(ScheduledTaskDTO scheduledTaskDTO ,ScheduledTaskRequestDTO scheduledTaskRequestDTO ,Long[] cinos,Long[] serviceDirNos){
		ScheduledTaskRequestDTO.dto2entity(scheduledTaskRequestDTO, scheduledTaskDTO.getRequestDTO());
		if(scheduledTaskRequestDTO!=null ){
			if(scheduledTaskRequestDTO.getAttrVals()!=null){
				scheduledTaskDTO.getRequestDTO().setAttrVals(scheduledTaskRequestDTO.getAttrVals());
			}
			scheduledTaskDTO.getRequestDTO().setEcategoryNo(scheduledTaskRequestDTO.getRequestCategoryNo());
		}
		if(cinos!=null && cinos.length>0){
			String str=longsConvertString(cinos);
			scheduledTaskDTO.getRequestDTO().setCiids(str);
		}
		if(serviceDirNos!=null && serviceDirNos.length>0){
			String str=longsConvertString(serviceDirNos);
			scheduledTaskDTO.getRequestDTO().setRequestServiceDirNos(str);
		}
		return scheduledTaskDTO;
	}
	
	/**
	 * 查询关联表单的数量
	 * @param formId
	 * @return
	 */
	public Integer findScheduledTaskNumByFormId(Long[] formIds){
		Integer num =scheduledTaskDAO.findScheduledTaskNumByFormId(formIds);
		return num;
	}
}
